﻿#if NETSTANDARD
using Microsoft.Extensions.Options;
#endif
using Org.BouncyCastle.Pkcs;
using PaySharp.Core;
using PaySharp.Core.Request;
using PaySharp.Core.Response;
using PaySharp.Core.Utils;
using PaySharp.Unionpay.Request;
using PaySharp.Unionpay.Response;
using System;
using System.IO;
using System.Threading.Tasks;

namespace PaySharp.Unionpay
{
    /// <summary>
    /// 银联支付网关
    /// </summary>
    public sealed class UnionpayGateway : BaseGateway
    {
        #region 私有字段

        private readonly Merchant _merchant;

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化银联支付网关
        /// </summary>
        /// <param name="merchant">商户数据</param>
        public UnionpayGateway(Merchant merchant)
            : base(merchant)
        {
#if DEBUG
            GatewayUrl = "https://gateway.test.95516.com/";
#else
            GatewayUrl = "https://gateway.95516.com/";
#endif
            _merchant = merchant;
            initSignCert(merchant.CertPath, merchant.CertPwd);
        }



        void initSignCert(string certPath, string certPwd)
        {
            FileStream fileStream = null;
            try
            {
                fileStream = new FileStream(certPath, FileMode.Open);

                Pkcs12Store store = new Pkcs12Store(fileStream, certPwd.ToCharArray());

                string pName = null;
                foreach (string n in store.Aliases)
                {
                    if (store.IsKeyEntry(n))
                    {
                        pName = n;
                        //break;
                    }
                }
                _merchant.CertKey = store.GetKey(pName).Key;
                X509CertificateEntry[] chain = store.GetCertificateChain(pName);
                _merchant.Cert = chain[0].Certificate;
                _merchant.CertId = _merchant.Cert.SerialNumber.ToString();

            }
            finally
            {
                if (fileStream != null)
                    fileStream.Close();
            }

        }

#if NETSTANDARD

        /// <summary>
        /// 初始化银联支付网关
        /// </summary>
        /// <param name="merchant">商户数据</param>
        public UnionpayGateway(IOptions<Merchant> merchant)
           : this(merchant.Value)
        {
        }

#endif

        #endregion

        #region 属性

        public override string GatewayUrl { get; set; }

        public new Merchant Merchant => _merchant;



        protected override string[] NotifyVerifyParameter => new string[]
        {
            "merId",  "respCode", "respMsg", "queryId", "signMethod"
        };

        #endregion

        public override NotifyResult ValidateNotify()
        {
            NotifyResult result = new NotifyResult();
            GatewayData gatewayData = NotifyProcess.ReadNotifyData();
            var response = gatewayData.ToObject<NotifyResponse>(StringCase.Snake);
            result.Response = response;
            result.Source = HttpUtil.RequestType == "GET" ? NotifySource.Sync : NotifySource.Async;
            result.Type = NotifyType.UnknownNotify; 
            if (response.TxnType == "TRADE_SUCCESS" && response.RespCode == "00")
            {
                result.Type = NotifyType.PaySuccess;
            }
            else if (response.TxnType == "04" && response.RespCode == "00")
            {
                result.Type = NotifyType.RefundSuccess;
            }
            else if (response.TxnType == "31" && response.RespCode == "00")
            {
                result.Type = NotifyType.RefundSuccess;
            } 
            bool signResult = SubmitProcess.CheckSign(gatewayData, response.Sign, response.SignPubKeyCert);
            if (signResult)
            {
                result.Status = NotifyStatus.ValidateSuccess;
            }
            else
            {
                result.Status = NotifyStatus.ValidateError;
            }
            return result;

        }

        public override TResponse Execute<TModel, TResponse>(Request<TModel, TResponse> request)
        {
            if (request is WebPayRequest || request is WapPayRequest)
            {
                return SubmitProcess.SdkExecute(_merchant, request, GatewayUrl);
            }

            return SubmitProcess.Execute(_merchant, request, GatewayUrl);
        }

        protected override void WriteFailureFlag()
        {
            HttpUtil.Current.Response.StatusCode = 404;
        }
    }
}
